package scuff.msg.json

import scuff.Surgeon
import scuff.msg._

/**
 * Reader of JSON messages of the format:
 * {{{
 * {
 *      "id": "<name>",
 *      "payload": <payload>
 * }
 * }}}
 * where `payload` is an optional field, with arbitrary data.
 */
trait DispatchingCharSeqJsonReader[CB] extends MessageReader[CharSequence] {
  private final val MsgParser = """(?s)\{\s*['"]?id['"]?\s*:\s*['"]([\w\.#$]+)['"]\s*,?\s*?(?:['"]?payload['"]?\s*:(.*))?\}""".r

  protected def callback: CB
  
  /** Materialize the JSON message into a typed payload object. */
  protected def materialize(id: String, payload: Option[String]): scuff.DoubleDispatch[CB]

  /** Receive JSON message and dispatch to callback. */
  def read(msg: CharSequence) {
    MsgParser.findFirstMatchIn(msg) match {
      case None ⇒ throw new IllegalArgumentException("Unexpected message format: " + msg)
      case Some(m) ⇒ {
        val id = m.group(1)
        val payload = Option(m.group(2))
        val message = materialize(id, payload)
        message.dispatch(callback)
      }
    }
  }

}
